﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using WinAPI.Advapi32;
using System.Management;
using WinAPI.kernel32;

namespace WinAPI.User32
{
    #region Nested type: POINT

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int x;
        public int y;
    }

    #endregion

    #region Nested type: RECT

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

    #endregion

    [StructLayout(LayoutKind.Sequential)]
    public class ShellExecuteInfo
    {
        public int cbSize;
        public int fMask;
        public IntPtr hwnd = IntPtr.Zero;
        public IntPtr lpVerb = IntPtr.Zero;
        public IntPtr lpFile = IntPtr.Zero;
        public IntPtr lpParameters = IntPtr.Zero;
        public IntPtr lpDirectory = IntPtr.Zero;
        public int nShow;
        public IntPtr hInstApp = IntPtr.Zero;
        public IntPtr lpIDList = IntPtr.Zero;
        public IntPtr lpClass = IntPtr.Zero;
        public IntPtr hkeyClass = IntPtr.Zero;
        public int dwHotKey;
        public IntPtr hIcon = IntPtr.Zero;
        public IntPtr hProcess = IntPtr.Zero;
        public ShellExecuteInfo()
        {
            this.cbSize = Marshal.SizeOf(this);
        }
    }

    public class User32Dll
    {
        #region Delegates

        public delegate bool EnumWindowsCallBack(IntPtr hwnd, string lParam);

        #endregion

        public const uint MK_LBUTTON = 0x0001;
        public const uint MK_RBUTTON = 0x0002;
        public const uint MK_SHIFT = 0x0004;
        public const uint MK_CONTROL = 0x0008;
        public const uint MK_MBUTTON = 0x0010;
        public const uint MK_XBUTTON1 = 0x0020;
        public const uint MK_XBUTTON2 = 0x0040;

        public const uint WM_MOUSEMOVE = 0x0200;
        public const uint WM_LBUTTONDOWN = 0x0201;
        public const uint WM_LBUTTONUP = 0x0202;
        public const uint WM_LBUTTONDBLCLK = 0x0203;
        public const uint WM_RBUTTONDOWN = 0x0204;
        public const uint WM_RBUTTONUP = 0x0205;
        public const uint WM_RBUTTONDBLCLK = 0x0206;
        public const uint WM_MBUTTONDOWN = 0x0207;
        public const uint WM_MBUTTONUP = 0x0208;
        public const uint WM_MBUTTONDBLCLK = 0x0209;

        public const uint MOD_ALT = 0x0001;
        public const uint MOD_CONTROL = 0x0002;
        public const uint MOD_SHIFT = 0x0004;
        public const uint MOD_WIN = 0x0008;

        public const uint WM_KEYFIRST = 0x0100;
        public const uint WM_KEYDOWN = 0x0100;
        public const uint WM_KEYUP = 0x0101;
        public const uint WM_CHAR = 0x0102;
        public const uint WM_DEADCHAR = 0x0103;
        public const uint WM_SYSKEYDOWN = 0x0104;
        public const uint WM_SYSKEYUP = 0x0105;
        public const uint WM_SYSCHAR = 0x0106;
        public const uint WM_SYSDEADCHAR = 0x0107;

        public const uint CB_GETEDITSEL = 0x0140;
        public const uint CB_LIMITTEXT = 0x0141;
        public const uint CB_SETEDITSEL = 0x0142;
        public const uint CB_ADDSTRING = 0x0143;
        public const uint CB_DELETESTRING = 0x0144;
        public const uint CB_DIR = 0x0145;
        public const uint CB_GETCOUNT = 0x0146;
        public const uint CB_GETCURSEL = 0x0147;
        public const uint CB_GETLBTEXT = 0x0148;
        public const uint CB_GETLBTEXTLEN = 0x0149;
        public const uint CB_INSERTSTRING = 0x014A;
        public const uint CB_RESETCONTENT = 0x014B;
        public const uint CB_FINDSTRING = 0x014C;
        public const uint CB_SELECTSTRING = 0x014D;
        public const uint CB_SETCURSEL = 0x014E;
        public const uint CB_SHOWDROPDOWN = 0x014F;
        public const uint CB_GETITEMDATA = 0x0150;
        public const uint CB_SETITEMDATA = 0x0151;
        public const uint CB_GETDROPPEDCONTROLRECT = 0x0152;
        public const uint CB_SETITEMHEIGHT = 0x0153;
        public const uint CB_GETITEMHEIGHT = 0x0154;
        public const uint CB_SETEXTENDEDUI = 0x0155;
        public const uint CB_GETEXTENDEDUI = 0x0156;
        public const uint CB_GETDROPPEDSTATE = 0x0157;
        public const uint CB_FINDSTRINGEXACT = 0x0158;
        public const uint CB_SETLOCALE = 0x0159;
        public const uint CB_GETLOCALE = 0x015A;


        public const uint WM_NULL = 0x0000;
        public const uint WM_CREATE = 0x0001;
        public const uint WM_DESTROY = 0x0002;
        public const uint WM_MOVE = 0x0003;
        public const uint WM_SIZE = 0x0005;

        public const uint WM_ACTIVATE = 0x0006;
        /*
         * WM_ACTIVATE state values
         */
        public const uint WA_INACTIVE = 0;
        public const uint WA_ACTIVE = 1;
        public const uint WA_CLICKACTIVE = 2;

        public const uint WM_SETFOCUS = 0x0007;
        public const uint WM_KILLFOCUS = 0x0008;
        public const uint WM_ENABLE = 0x000A;
        public const uint WM_SETREDRAW = 0x000B;
        public const uint WM_SETTEXT = 0x000C;
        public const uint WM_GETTEXT = 0x000D;
        public const uint WM_GETTEXTLENGTH = 0x000E;
        public const uint WM_PAINT = 0x000F;
        public const uint WM_CLOSE = 0x0010;

        public const uint WM_QUERYENDSESSION = 0x0011;
        public const uint WM_QUERYOPEN = 0x0013;
        public const uint WM_ENDSESSION = 0x0016;

        public const uint WM_QUIT = 0x0012;
        public const uint WM_ERASEBKGND = 0x0014;
        public const uint WM_SYSCOLORCHANGE = 0x0015;
        public const uint WM_SHOWWINDOW = 0x0018;
        public const uint WM_WININICHANGE = 0x001A;

        public const uint WM_DEVMODECHANGE = 0x001B;
        public const uint WM_ACTIVATEAPP = 0x001C;
        public const uint WM_FONTCHANGE = 0x001D;
        public const uint WM_TIMECHANGE = 0x001E;
        public const uint WM_CANCELMODE = 0x001F;
        public const uint WM_SETCURSOR = 0x0020;
        public const uint WM_MOUSEACTIVATE = 0x0021;
        public const uint WM_CHILDACTIVATE = 0x0022;
        public const uint WM_QUEUESYNC = 0x0023;

        public const uint WM_GETMINMAXINFO = 0x0024;

        public const int SE_PRIVILEGE_ENABLED = 0x00000002;
        public const int TOKEN_QUERY = 0x00000008;
        public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
        public const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
        public const int EWX_LOGOFF = 0x00000000;
        public const int EWX_SHUTDOWN = 0x00000001;
        public const int EWX_REBOOT = 0x00000002;
        public const int EWX_FORCE = 0x00000004;
        public const int EWX_POWEROFF = 0x00000008;
        public const int EWX_FORCEIFHUNG = 0x00000010;


        [DllImport("user32.dll")]
        public static extern IntPtr WindowFromPoint(POINT point);

        [DllImport("user32.dll")]
        public static extern int EnableWindow(IntPtr hWnd, int bEnable);

        [DllImport("user32.dll")]
        public static extern int GetCursorPos(ref POINT lpPoint);

        [DllImport("user32.dll")]
        public static extern IntPtr ChildWindowFromPoint(IntPtr hWndParent, POINT point);

        [DllImport("user32.dll")]
        public static extern int ScreenToClient(IntPtr hWnd, ref POINT lpPoint);

        [DllImport("User32.dll")]
        public static extern int RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        public static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        public static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, StringBuilder lParam);

        [DllImport("User32.dll")]
        public static extern int PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

        [DllImport("User32.dll")]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("User32.dll")]
        public static extern int SetWindowText(IntPtr hWnd, string lpString);

        [DllImport("user32")]
        public static extern int EnumWindows(EnumWindowsCallBack callBack, string value);

        [DllImport("user32")]
        public static extern int GetClientRect(IntPtr hWnd, ref RECT lpRect);

        [DllImport("user32")]
        public static extern int GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        [DllImport("user32")]
        public static extern int SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32")]
        public static extern uint GetDlgItemText(IntPtr hDlg, int nIdDlgItem, StringBuilder lpString, int nMaxCount);

        [DllImport("user32")]
        public static extern int GetDlgCtrlID(IntPtr hwndCtl);

        [DllImport("user32")]
        public static extern int SendDlgItemMessage(IntPtr hDlg, int nIDDlgItem, uint Msg, IntPtr wParam, IntPtr lParam);

        public static IntPtr MakeLParam(int low, int hight)
        {
            return (IntPtr)(hight << 16 | low);
        }

        [DllImport("User32.dll")]
        public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        [DllImport("User32.dll")]
        public static extern byte MapVirtualKey(byte uCode, byte uMapType);

        [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
        internal static extern bool ExitWindowsEx(int flg, int rea);

        [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool ShellExecuteEx(ShellExecuteInfo info);


        private static void DoExitWin(int flg)
        {
            Advapi32Dll.TokPriv1Luid tp;
            IntPtr hproc = Kernel32Dll.GetCurrentProcess();
            IntPtr htok = IntPtr.Zero;
            bool ok = Advapi32Dll.OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
            tp.Count = 1;
            tp.Luid = 0;
            tp.Attr = SE_PRIVILEGE_ENABLED;
            ok = Advapi32Dll.LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
            ok = Advapi32Dll.AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
            ok = ExitWindowsEx(flg, 0);
        }

        public static void Reboot()
        {
            DoExitWin(EWX_REBOOT);
        }

        public static void ShutDown()
        {
            DoExitWin(EWX_SHUTDOWN);
        }

    }
}
